package bview

import (
	"fmt"
	//"html/template"

	//"io/ioutil"
	"bmodel"
	"net/http"
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
)

/***********************************LOGIN/INDEX**************************************/

/*
 * cms login GET
 * para none
 * return 200, html
 */
func CmsloginGET(c *gin.Context) {
	c.HTML(200, "cms/login.html", gin.H{})
}

/*
 * cms login POST:
 * para, see "struct cmsuserData" in detail
 * return 200, String: code#content,  code is (0 success/1 false), content is string
 */
func CmsloginPOST(c *gin.Context) {
	var catchedcmsUserData cmsuserData
	if c.ShouldBindJSON(&catchedcmsUserData) != nil {
		parseSendPOST(c, ERROR_POST_PARA_ERROR, POSTERR)
	} else {
		if merr := bmodel.CmsCheckuserIsExist(catchedcmsUserData.Username, catchedcmsUserData.Password); merr != nil {
			parseSendPOST(c, fmt.Sprintf("%s", merr), POSTERR)
		} else {
			http.SetCookie(c.Writer, &http.Cookie{
				Name: "cmsusername", Value: catchedcmsUserData.Username,
				Expires: time.Now().Add(LOGIN_SESSION_TIME_S * time.Second),
			})
			http.SetCookie(c.Writer, &http.Cookie{
				Name: "cmspassword", Value: catchedcmsUserData.Password,
				Expires: time.Now().Add(LOGIN_SESSION_TIME_S * time.Second),
			})
			parseSendPOST(c, OK_LOGIN_SUCCESS, POSTOK)
		}
	}
}

/*
 * cms logout GET
 * para none
 * return 302
 */
func CmslogoutGET(c *gin.Context) {
	http.SetCookie(c.Writer, &http.Cookie{
		Name: "cmsusername", Value: "",
		Expires: time.Now().Add(-1 * time.Second),
	})
	http.SetCookie(c.Writer, &http.Cookie{
		Name: "cmspassword", Value: "",
		Expires: time.Now().Add(-1 * time.Second),
	})
	c.Redirect(302, "/cms/login.html")
}

/*
 * cms index GET
 * para none
 * return 302
 */
func CmsindexGET(c *gin.Context) {
	//这里有一些数据库操作..
	blockNums, errb := bmodel.Countblocks()
	if errb != nil {
		c.String(200, fmt.Sprintf("%s", errb))
		return
	}
	articleNums, errp := bmodel.Countarticles(false)
	if errp != nil {
		c.String(200, fmt.Sprintf("%s", errp))
		return
	}
	c.HTML(200, "cms/index.html", gin.H{
		"blockNums":   blockNums,
		"articleNums": articleNums,
	})
}

/***********************************BLOCK**************************************/

/*
 * cms blocklist get
 * para c *gin.Context(GET para: page, perpage)
 * return 200, html/String
 */
func CmsblocklistGET(c *gin.Context) {
	blockPage := c.DefaultQuery("page", DEFAULT_BLOCK_LIST_PAGE_STRING)
	blockPerpage := c.DefaultQuery("perpage", DEFAULT_NUMBER_OF_BLOCK_IN_ONE_PAGE)
	var blockPageInt, blockPerpageInt int
	var errbpi, errbppi error
	blockPageInt, errbpi = strconv.Atoi(blockPage)
	blockPerpageInt, errbppi = strconv.Atoi(blockPerpage)

	if errbpi != nil || errbppi != nil {
		c.String(200, ERROR_GET_PARA_ERROR)
		return
	}

	if blockContents, merr := bmodel.GetblocksByPage(blockPageInt, blockPerpageInt); merr != nil {
		c.String(200, fmt.Sprintf("%s", merr))
	} else {
		blockNums, errb := bmodel.Countblocks()
		if errb != nil {
			c.String(200, fmt.Sprintf("%s", errb))
			return
		}

		pageIndexs := bmodel.GeneratePages(blockNums, DEFAULT_NUMBER_OF_PAGES,
			blockPageInt, blockPerpageInt)

		var retMap = make(map[string]interface{})
		retMap["defset"] = bmodel.GetblockDefaultSettings()
		retMap["content"] = blockContents
		retMap["pageIndexs"] = pageIndexs
		retMap["perpage"] = blockPerpage
		c.HTML(200, "cms/blocklist.html", retMap)
	}
}

/*
 * cms blockadd get
 * para c *gin.Context
 * return 200, html/String
 */
func CmsblockaddGET(c *gin.Context) {
	topblockinfos, terr := bmodel.GetPublishedToplevelBlockIdsAndNames()
	if terr == nil {
		var retMap = make(map[string]interface{})
		retMap["defset"] = bmodel.GetblockDefaultSettings()
		retMap["topblockinfos"] = topblockinfos
		c.HTML(200, "cms/blockadd.html", retMap)
	} else {
		c.String(200, fmt.Sprintf("%s", terr))
		return
	}
}

/*
 * cms blockadd post:
 * para: see "struct blockaddData" in detail
 * return 200, String: code#content,  code is (0 success/1 false), content is string
 */
func CmsblockaddPOST(c *gin.Context) {
	var catchedblockaddData blockaddData
	if c.ShouldBindJSON(&catchedblockaddData) != nil {
		parseSendPOST(c, ERROR_POST_PARA_ERROR, POSTERR)
	} else {

		if merr := bmodel.Addblock(catchedblockaddData.Parentid, catchedblockaddData.Title, catchedblockaddData.Describe,
			catchedblockaddData.State); merr != nil {
			parseSendPOST(c, fmt.Sprintf("%s", merr), POSTERR)
		} else {
			parseSendPOST(c, OK_BLOCK_ADD_SUCCESS, POSTOK)
		}
	}
}

/*
 * cms blockedit get
 * para c *gin.Context(GER para: id)
 * return 200, html/String
 */
func CmsblockeditGET(c *gin.Context) {
	blockId := c.DefaultQuery("id", DEFAULT_BLOCK_ID)
	var blockIdInt int
	var errbii error
	blockIdInt, errbii = strconv.Atoi(blockId)

	if errbii != nil {
		c.String(200, ERROR_GET_PARA_ERROR)
		return
	}

	if blockContent, merr := bmodel.GetblockById(blockIdInt); merr != nil {
		c.String(200, fmt.Sprintf("%s", merr))
	} else {
		topblockinfos, terr := bmodel.GetPublishedToplevelBlockIdsAndNames()
		if terr == nil {
			var retMap = make(map[string]interface{})
			retMap["defset"] = bmodel.GetblockDefaultSettings()
			retMap["content"] = blockContent
			retMap["topblockinfos"] = topblockinfos
			c.HTML(200, "cms/blockedit.html", retMap)
		} else {
			c.String(200, fmt.Sprintf("%s", terr))
			return
		}

	}
}

/*
 * cms blockedit post:
 * para: see "struct blockeditData" in detail
 * return 200, String: code#content,  code is (0 success/1 false), content is string
 */
func CmsblockeditPOST(c *gin.Context) {
	var catchedblockeditData blockeditData
	if c.ShouldBindJSON(&catchedblockeditData) != nil {
		parseSendPOST(c, ERROR_POST_PARA_ERROR, POSTERR)
	} else {
		var blockIdInt int
		var errbii error
		blockIdInt, errbii = strconv.Atoi(catchedblockeditData.Id)

		if errbii != nil {
			c.String(200, ERROR_GET_PARA_ERROR)
			return
		}
		if merr := bmodel.EditblockById(blockIdInt, catchedblockeditData.Parentid, catchedblockeditData.Title,
			catchedblockeditData.Describe, catchedblockeditData.State); merr != nil {
			parseSendPOST(c, fmt.Sprintf("%s", merr), POSTERR)
		} else {
			parseSendPOST(c, OK_BLOCK_EDIT_SUCCESS, POSTOK)
		}
	}
}

/***********************************ARTICLE*************************************/

/*
 * cms articlelist get
 * para c *gin.Context(GET para: page, perpage)
 * return 200, html/String
 */
func CmsarticlelistGET(c *gin.Context) {
	articlePage := c.DefaultQuery("page", DEFAULT_ARTICLE_LIST_PAGE_STRING)
	articlePerpage := c.DefaultQuery("perpage", DEFAULT_NUMBER_OF_ARTICLE_IN_ONE_PAGE)
	var articlePageInt, articlePerpageInt int
	var errppi, errpppi error
	articlePageInt, errppi = strconv.Atoi(articlePage)
	articlePerpageInt, errpppi = strconv.Atoi(articlePerpage)

	if errppi != nil || errpppi != nil {
		c.String(200, ERROR_GET_PARA_ERROR)
		return
	}

	if articleContents, merr := bmodel.GetarticlesByPage(articlePageInt, articlePerpageInt); merr != nil {
		//if _, merr := bmodel.GetarticlesByPage(articlePageInt, articlePerpageInt); merr != nil {
		c.String(200, fmt.Sprintf("%s", merr))
	} else {
		var retMap = make(map[string]interface{})

		articleNums, errb := bmodel.Countarticles(false)
		if errb != nil {
			c.String(200, fmt.Sprintf("%s", errb))
			return
		}

		pageIndexs := bmodel.GeneratePages(articleNums, DEFAULT_NUMBER_OF_PAGES,
			articlePageInt, articlePerpageInt)
		retMap["pageIndexs"] = pageIndexs
		retMap["perpage"] = articlePerpage

		retMap["defset"] = bmodel.GetarticleDefaultSettings()
		for index := 0; index < len(articleContents); index++ {
			articleContents[index]["Keywords"] = CustomFormat_lengthNotGreaterThan(articleContents[index]["Keywords"], 30)
			articleContents[index]["Remark"] = CustomFormat_lengthNotGreaterThan(articleContents[index]["Remark"], 5)
		}

		retMap["content"] = articleContents
		c.HTML(200, "cms/articlelist.html", retMap)
	}
}

/*
 * cms articleadd get
 * para c *gin.Context
 * return 200, html
 */
func CmsarticleaddGET(c *gin.Context) {
	blockinfos, erro := bmodel.GetPublishedSublevelBlockIdsAndNames()
	if erro != nil {
		c.String(200, fmt.Sprintf("%s", erro))
	} else {
		var retMap = make(map[string]interface{})
		retMap["defset"] = bmodel.GetarticleDefaultSettings()
		retMap["blockinfos"] = blockinfos

		c.HTML(200, "cms/articleadd.html", retMap)
	}
}

/*
 * cms articleadd post:
 * para: see "struct articleaddData" in detail
 * return 200, String: code#content,  code is (0 success/1 false), content is string
 */
func CmsarticleaddPOST(c *gin.Context) {
	var catchedarticleaddData articleaddData
	if c.ShouldBindJSON(&catchedarticleaddData) != nil {
		parseSendPOST(c, ERROR_POST_PARA_ERROR, POSTERR)
	} else {
		if merr := bmodel.Addarticle(
			catchedarticleaddData.Articleblockid,
			catchedarticleaddData.Articlepriority,
			catchedarticleaddData.Articletitle,
			catchedarticleaddData.Articlekeywords,
			catchedarticleaddData.Articlebrief,
			catchedarticleaddData.Articlecontent,
			"0", //for type, 0 is default dump value, 以后版本也许会赋有意义的值
			catchedarticleaddData.Articleremark,
			catchedarticleaddData.Articlestate,
		); merr != nil {
			parseSendPOST(c, fmt.Sprintf("%s", merr), POSTERR)
		} else {
			parseSendPOST(c, OK_ARTICLE_ADD_SUCCESS, POSTOK)
		}
	}
}

/*
 * cms articleedit get
 * para c *gin.Context(GER para: id)
 * return 200, html/String
 */
func CmsarticleeditGET(c *gin.Context) {
	blockinfos, erro := bmodel.GetPublishedSublevelBlockIdsAndNames()
	if erro != nil {
		c.String(200, fmt.Sprintf("%s", erro))
	} else {
		articleId := c.DefaultQuery("id", DEFAULT_ARTICLE_ID)
		var articleIdInt int
		var errpii error
		articleIdInt, errpii = strconv.Atoi(articleId)

		if errpii != nil {
			c.String(200, ERROR_GET_PARA_ERROR)
			return
		}

		if articleContent, merr := bmodel.GetarticleById(articleIdInt); merr != nil {
			c.String(200, fmt.Sprintf("%s", merr))
		} else {
			//note: describe is a html
			var retMap = make(map[string]interface{})
			retMap["defset"] = bmodel.GetarticleDefaultSettings()
			retMap["content"] = articleContent
			retMap["blockinfos"] = blockinfos
			c.HTML(200, "cms/articleedit.html", retMap)
		}
	}
}

/*
 * cms articleedit post:
 * para: see "struct articleeditData" in detail
 * return 200, String: code#content,  code is (0 success/1 false), content is string
 */
func CmsarticleeditPOST(c *gin.Context) {
	var catchedarticleeditData articleeditData

	if c.ShouldBindJSON(&catchedarticleeditData) != nil {
		parseSendPOST(c, ERROR_POST_PARA_ERROR, POSTERR)
	} else {
		var articleIdInt int
		var errbii error
		articleIdInt, errbii = strconv.Atoi(catchedarticleeditData.Articleid)

		if errbii != nil {
			c.String(200, ERROR_POST_PARA_ERROR)
			return
		}

		if merr := bmodel.EditarticlesById(
			articleIdInt,
			catchedarticleeditData.Articleblockid,
			catchedarticleeditData.Articlepriority,
			catchedarticleeditData.Articletitle,
			catchedarticleeditData.Articlekeywords,
			catchedarticleeditData.Articlebrief,
			catchedarticleeditData.Articlecontent,
			"0", //for type, 0 is default dump value, 以后版本也许会赋有意义的值
			catchedarticleeditData.Articleremark,
			catchedarticleeditData.Articlestate,
		); merr != nil {
			parseSendPOST(c, fmt.Sprintf("%s", merr), POSTERR)
		} else {
			parseSendPOST(c, OK_ARTICLE_EDIT_SUCCESS, POSTOK)
		}
	}
}

/*
 * check if cms login, middleware, get method
 * have c.About() inside
 */
func CmscheckloginstateGET(c *gin.Context) {
	username, _ := c.Cookie("cmsusername")
	password, _ := c.Cookie("cmspassword")
	if merr := bmodel.CmsCheckuserIsExist(username, password); merr != nil {
		c.Abort()
		c.Redirect(302, "/cms/login.html")
		// return can be neglected, if Abort() before, then the latter handler func will not exec
		return
	} else {
		c.Next()
	}
}

/*
 * check if cms login, middleware, post method
 * have c.About() inside
 */
func CmscheckloginstatePOST(c *gin.Context) {
	username, _ := c.Cookie("cmsusername")
	password, _ := c.Cookie("cmspassword")
	if merr := bmodel.CmsCheckuserIsExist(username, password); merr != nil {
		c.Abort()
		parseSendPOST(c, ERROR_LOGIN_STATE_TIMEOUT, POSTERR)
		// return can be neglected, if Abort() before, then the latter handler func will not exec
		return
	} else {
		c.Next()
	}
}
